using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Diagnostics;
using System.Xml;
using System.Xml.Schema; 
using XPathParser; 
using System.Xml.Linq; 
using System.Xml.XPath;

namespace CodeGenerationPipelineInterface
{
	[DebuggerDisplay("{ DebugInfo }")]
	public class Initialization : IXmlElement
	{
        private IXmlDocument document;
        private XNode node;
        private ManagedList<Instantiate> instantiates;
        private ManagedList<Declare> declares;
        private const int unbounded = int.MaxValue;

		public Initialization(IXmlDocument document)
		{
           instantiates = new ManagedList<Instantiate>("Instantiates", "Initialization.Instantiates", 0, 0);
           declares = new ManagedList<Declare>("Declares", "Initialization.Declares", 0, 0);
            
            this.document = document;
		}

        public IXmlDocument Document 
        { 
            get
            {
                return document;
            }

            set
            {
                document = value;
            }
        }

		[XPathAttribute("/ElementBuild/Elements/Root/ChildElements/Element/Operations/Operation/Initialization/Instantiate")]
		[MinOccursAttribute(0)]
 
		public ManagedList<Instantiate> Instantiates
		{
			get
			{
				return instantiates;
			}
		}

		[XPathAttribute("/ElementBuild/Elements/Root/ChildElements/Element/Operations/Operation/Initialization/Declare")]
		[MinOccursAttribute(0)]
 
		public ManagedList<Declare> Declares
		{
			get
			{
				return declares;
			}
		}

		public string ElementName
		{
			get
			{
				return "Initialization";
			}
		}

		public string DebugInfo
		{
			get
			{
				return "Initialization";
			}
		}

        public XNode Node
        {
            get
            {
                return node;
            }
        }

        public IEnumerable<string> CDataElements
        {
            get
            {
                var element = (XElement)node;

                return element.Nodes().Where(n => n is XCData).Cast<XCData>().Select(c => c.Value);
            }
        }

        public void Read(XNode node)
        {
            var elementNode = (XElement) node;
            var prefix = elementNode.GetPrefixOfNamespace(elementNode.Name.Namespace);

            // Instantiate

            foreach (var elementInstantiate in node.XPathSelectElements(prefix + ":Instantiate", this.Document.NamespaceManager))
            {
                var instantiate = new Instantiate(this.Document);

                instantiate.Read(elementInstantiate);

                this.instantiates.Add(instantiate);
            }

            // Declare

            foreach (var elementDeclare in node.XPathSelectElements(prefix + ":Declare", this.Document.NamespaceManager))
            {
                var declare = new Declare(this.Document);

                declare.Read(elementDeclare);

                this.declares.Add(declare);
            }

            this.node = node;
        }

        public void Write(XNode parentNode, XNamespace elementNamespace)
        {
            var parentElement = (XElement)parentNode;
            var element = new XElement(elementNamespace + this.ElementName);

            parentElement.Add(element);


            foreach (var instantiates in this.Instantiates)
            {
                instantiates.Write(element, elementNamespace);
            }

            foreach (var declares in this.Declares)
            {
                declares.Write(element, elementNamespace);
            }

        }

        public void Write(XDocument document, XmlNamespaceManager namespaces)
        {
            var namespaceAttributes = namespaces.Cast<string>().Where(s => !string.IsNullOrEmpty(s) && s != "xmlns" && s != "xml").Select(s => new XAttribute(XNamespace.Xmlns + s, XNamespace.Get(namespaces.LookupNamespace(s))));
            var element = new XElement(this.document.ElementNamespace + this.ElementName, namespaceAttributes.ToArray<object>());

            document.Add(element);

            foreach (var instantiates in this.Instantiates)
            {
                instantiates.Write(element, this.Document.ElementNamespace);
            }

            foreach (var declares in this.Declares)
            {
                declares.Write(element, this.Document.ElementNamespace);
            }

        }

        public bool Validate(object sender, ValidationEventHandler handler)
        {
            var valid = true;
            foreach (Instantiate instantiates in this.Instantiates)
            {
                instantiates.Validate(sender, (sender2, e) =>
                {
                    handler(sender2, e);
                    valid = false;
                });
			}

            foreach (Declare declares in this.Declares)
            {
                declares.Validate(sender, (sender2, e) =>
                {
                    handler(sender2, e);
                    valid = false;
                });
			}

            return valid;
        }
    }
}
